package com.yuanlang.common.util;

import java.io.ByteArrayOutputStream;
import java.security.Key;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.Signature;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;

import javax.crypto.Cipher;

import org.apache.commons.codec.binary.Base64;

/**
 * <p>
 *  rsa 加密工具
 */
public class RSAUtils {
	
	public static String privateKey = "MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBALqKI95Q5omg4Tlmp/Ytb70gdK3pyIDky0A6aIJ8bSzxmJD40smCCI8SwsmVygN1uBofPofzqImTjuRsM4JJ2HWFC3fA70SHTLBXY0to6iDISuKdO8wm5+mnI2F1HuSq0+1VILFwdFwomQwOEj7KiDz2URcpuAieGSprVVUCRNVnAgMBAAECgYBSaw6F/4CcdnSMhArZ/iFMkrZ60LxCFtSmwCfE32ztWqFqDEY1ujpF3KgroP7soGqDQCLEtqdUgdm0mwn3GuGD6ev8EJGP0uvfTIrFz3sak3GA+9r4k+oHD+gIKoFNe4hgjbh91nmrO1CWRhLIr+Tn92ugT2Yg3UCuAWFlv00uoQJBAN7p71YBasEIHsUdWBH1bPdgG0AFzPhqw0BG8q7LavWENUiiHDXN3Z2ikwfL017MDQkTukTWu6iaNzP8elJ/BA0CQQDWOhfice6HZLHj8h33/tVsuu1wafphx2xnyd2wbDr3Em6vcUo7L2ibwyVCUFUeKvLQmTSfgnzGzUClKFexMl5DAkEAybkzgEY6AEND7Sc36tCJcneDUXWuXmPnG4TY2vt0aIfi3D7vfnU1BxD3M0ftmMzZQwyaNO+J1PLx39asL3mIBQJBALyFaQlsq7VYZrerFLZt+tFxeowHp0Cu53Y6ji24QPe2r9MSxnlpEgyo4bwGx7EBqKbrfAS3Jykn7TCqXOlh4tMCQQCeTzt11ysqAekklt8YZZ4bABf7ipwmjkXC4uJZuo5P8we7Az5mfXNrv6unGQNyIX0xefkhH1ztg2/MxaA8rx7b";//私钥

    /**
     * 加密算法RSA
     */
    public static final String KEY_ALGORITHM = "RSA";
    
    /**
     * 签名算法
     */
    public static final String SIGNATURE_ALGORITHM = "MD5withRSA";
    
    /**
     * RSA最大加密明文大小
     */
    private static final int MAX_ENCRYPT_BLOCK = 117;

    
    /**
     * <p>
     * 用私钥对信息生成数字签名
     * </p>
     * 
     * @param data 已加密数据
     * @param privateKey 私钥(BASE64编码)
     * 
     * @return
     * @throws Exception
     */
    public static String sign(byte[] data, String privateKey) throws Exception {
        byte[] keyBytes = decode(privateKey);
        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        PrivateKey privateK = keyFactory.generatePrivate(pkcs8KeySpec);
        Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
        signature.initSign(privateK);
        signature.update(data);
        return encode(signature.sign());
    }
    

    /**
     * <p>
     * 私钥加密
     * </p>
     * 
     * @param data 源数据
     * @param privateKey 私钥(BASE64编码)
     * @return
     * @throws Exception
     */
    public static byte[] encryptByPrivateKey(byte[] data, String privateKey)
            throws Exception {
        byte[] keyBytes =decode(privateKey);
        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        Key privateK = keyFactory.generatePrivate(pkcs8KeySpec);
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.ENCRYPT_MODE, privateK);
        int inputLen = data.length;
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int offSet = 0;
        byte[] cache;
        int i = 0;
        // 对数据分段加密
        while (inputLen - offSet > 0) {
            if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {
                cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK);
            } else {
                cache = cipher.doFinal(data, offSet, inputLen - offSet);
            }
            out.write(cache, 0, cache.length);
            i++;
            offSet = i * MAX_ENCRYPT_BLOCK;
        }
        byte[] encryptedData = out.toByteArray();
        out.close();
        return encryptedData;
    }

    /**
     * base64 加密
     * @param bytes
     * @return
     * @throws Exception
     */
    public static String encode(byte[] bytes) throws Exception {
        return new String(Base64.encodeBase64(bytes));
    }
    
    /**
     * base64 解密
     * @param base64
     * @return
     * @throws Exception
     */
    public static byte[] decode(String base64) throws Exception {
        return Base64.decodeBase64(base64.getBytes());
    }

    
    /**
     * 签名生成算法：将参数名按字典序升序进行排序，然后将所有参数按"key=value"格式拼接在一起，以“&”分隔
     *
     * @param params 请求参数集，所有参数必须已转换为字符串类型并进行encode
     * @param privateKey 签名密钥
     * @return 签名
     * @throws Exception
     */
    public static String getSignature(Map<String, String> params, String privateKey) throws Exception {
        //将Map转换为TreeMap实现参数以其参数名的字典序升序进行排序
        Map<String, String> sortedParams = new TreeMap<String, String>(params);
        Set<Map.Entry<String, String>> entrySet = sortedParams.entrySet();

        //遍历排序后的字典，将所有参数按"key=value"格式拼接在一起
        StringBuilder baseString = new StringBuilder();
        for (Map.Entry<String, String> param : entrySet) {
            if("sign".equals(param.getKey())){
                continue;
            }
            baseString.append(param.getKey()).append("=").append(param.getValue()).append("&");
        }

        baseString.deleteCharAt(baseString.length() - 1);
        System.out.println("baseString : "+baseString);
        byte[] privateBytes= RSAUtils.encryptByPrivateKey(baseString.toString().getBytes(), privateKey);
        return RSAUtils.sign(privateBytes, privateKey);
    }
    
    public static void main(String[] args) throws Exception {
          Map<String, String> params = new HashMap<String, String>();
          params.put("idNo", "110101198001010037");
          params.put("channel", "YLQBHY");
          
          System.out.println(RSAUtils.getSignature(params, privateKey));
          //kGhJiatlVYHzVJf36hKzJE6P11Heeib43/I46FN4ZYx8FqzdVTQbToRmaEZ6/dPH0KNbYPrfBpE4zII4VQ0Kz5sSIOIArbLpRCXlgV4MK9d6v9gu6uk0XHwimu7pyvsCVL0DBvJ2XUyHivRdxn++R1BTAEWycCq9cVukVrzcm3Q=
    }
    
    
}